/**
 * Copyright (C) 2012 The SkyTvOS Project
 * <p/>
 * Version     Date           Author
 * ─────────────────────────────────────
 * 2013-10-29         Rico
 */

package com.skyworth.tvos.ipcservice;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;

import com.skyworth.framework.skysdk.ipc.ICmdReceiver;
import com.skyworth.framework.skysdk.ipc.IIPCConnector;
import com.skyworth.framework.skysdk.schema.ParcelableUtil;
import com.skyworth.framework.skysdk.schema.SkyCmdHeader;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

public class SkyIPCService extends Service {
    @Override
    public void onCreate() {
        super.onCreate();
        // 此处屏蔽启动deservic，报名不一样。
        // ServiceDispatch.getInstance().init();
        // ServiceDispatch.getInstance().startServices();
        // CheckerManager.getChecker().start();
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return mIPCStub;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);
    }

    @Override
    public void onRebind(Intent intent) {
        super.onRebind(intent);
    }

    /**
     * <p>
     * 远程aidl回调接口
     * </p>
     * <p>
     * 如果外部远程接口进入died状态会回调到该类的oncallbackdied方法
     * </p>
     *
     * @author Rico
     * @version V100.000.000
     * @ClassName SkyRemoteCallBackList
     * @date 2013-10-29
     */
    public class SkyRemoteCallBackList extends RemoteCallbackList<ICmdReceiver> {
        @Override
        public void onCallbackDied(ICmdReceiver callback) {
            Log.d("IPCService", "onCallBackDied!");

            removeDiedCallBack(callback);
            super.onCallbackDied(callback);
        }
    }

    private SkyRemoteCallBackList skyRemoteCallBackList = new SkyRemoteCallBackList();
    private ConcurrentHashMap<Integer, ICmdReceiver> cmdReceiverMap = new ConcurrentHashMap<Integer, ICmdReceiver>();

    private static AtomicInteger currenttransportId = new AtomicInteger(1);
    private ConcurrentHashMap<String, Integer> tansportIdMap = new ConcurrentHashMap<String, Integer>();

    // private AvroData<SkyCmdHeader> headerutil = new AvroData<SkyCmdHeader>();

    private void removeDiedCallBack(ICmdReceiver callback) {
        for (Integer key : cmdReceiverMap.keySet()) {
            if (cmdReceiverMap.get(key).equals(callback)) {
                cmdReceiverMap.remove(key);
                for (String strKey : tansportIdMap.keySet()) {
                    if (tansportIdMap.get(strKey) == key) {
                        tansportIdMap.remove(strKey);
                        break;
                    }
                }
                break;
            }
        }
    }

    private final IIPCConnector.Stub mIPCStub = new IIPCConnector.Stub() {

        @Override
        public int getTransportID() throws RemoteException {
            // TODO Auto-generated method stub
            return currenttransportId.getAndIncrement();
        }

        @Override
        public void send(int target, byte[] header, byte[] body) throws RemoteException {
            // TODO Auto-generated method stub
            ICmdReceiver receiver = cmdReceiverMap.get(target);
            if (receiver != null) {
                SkyCmdHeader cmdheader = ParcelableUtil.unmarshall(header, SkyCmdHeader.CREATOR);// headerutil.deseriaze(header).get(0);
                int source = Integer.valueOf(cmdheader.getSourceId().toString());

                try {
                    receiver.onReceive(source, header, body);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        @Override
        public byte[] sendWithAck(int target, byte[] header, byte[] body) throws RemoteException {
            // TODO Auto-generated method stub
            ICmdReceiver receiver = cmdReceiverMap.get(target);
            if (receiver != null) {
                SkyCmdHeader cmdheader = ParcelableUtil.unmarshall(header, SkyCmdHeader.CREATOR);
                int source = Integer.valueOf(cmdheader.getSourceId().toString());

                try {
                    byte[] recbyte = receiver.onReceiveSync(source, header, body);
                    if (recbyte == null) {
                        recbyte = new byte[0];
                    }
                    return recbyte;
                } catch (Exception e) {
                    e.printStackTrace();
                    return new byte[0];
                }
            }
            return new byte[0];
        }

        @Override
        public void addReceiver(int target, String path, ICmdReceiver receiver)
                throws RemoteException {
            // TODO Auto-generated method stub
            tansportIdMap.put(path, target);
            skyRemoteCallBackList.register(receiver);
            cmdReceiverMap.put(target, receiver);
        }

        @Override
        public int getTargetTransportID(String path) throws RemoteException {
            // TODO Auto-generated method stub
            if (tansportIdMap.containsKey(path)) {
                return tansportIdMap.get(path);
            }
            return 0;
        }

        @Override
        public void removeReceiver(int target) throws RemoteException {
            // TODO Auto-generated method stub
            ICmdReceiver receiver = cmdReceiverMap.remove(target);
            if (receiver != null) {
                skyRemoteCallBackList.unregister(receiver);
            }
            for (String key : tansportIdMap.keySet()) {
                if (target == tansportIdMap.get(key)) {
                    tansportIdMap.remove(key);
                    break;
                }
            }
        }

    };
}
